package com.xuan.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuan.entity.dto.*;
import com.xuan.entity.po.User;
import com.xuan.entity.po.UserRoles;
import com.xuan.entity.result.PageResult;
import com.xuan.entity.result.Result;
import com.xuan.entity.vo.QueryLoggingMessage;
import com.xuan.entity.vo.UserInfoVO;
import com.xuan.entity.vo.UserVO;
import com.xuan.enums.RoleCode;
import com.xuan.enums.UserAction;
import com.xuan.mapper.UsersMapper;
import com.xuan.rpc.PermissionService;
import com.xuan.service.IUsersService;
import com.xuan.utils.CaptchaUtil;
import com.xuan.utils.JwtTokenUtil;
import com.xuan.utils.SnowflakeIdGenerator;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;


import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.xuan.constants.CommonConstants.*;
import static com.xuan.constants.SystemConstants.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author xuan
 * @since 2025-06-12
 */
@Service
@RequiredArgsConstructor
@Slf4j(topic = "UserServiceImpl")
public class UsersServiceImpl extends ServiceImpl<UsersMapper, User> implements IUsersService {
    private final UsersMapper usersMapper;
    private final CaptchaUtil captchaUtil;
    private final RabbitTemplate rabbitTemplate;
    private final RedisTemplate<String, Object> redisTemplate;
    private final SnowflakeIdGenerator snowflakeIdGenerator;
    private final PermissionService permissionService;
    /**
     * 分页用户列表
     * 根据权限校验结果返回：普通用户仅自己，管理员所有普通用户，超管全部
     * @param userId
     * @param usersPageDTO
     * @return
     */
    @Override
    public PageResult<UserInfoVO> getUsers(Long userId, UsersPageDTO usersPageDTO, HttpServletRequest request) {
        String userRole = permissionService.getUserRoleCode(userId).getData();
        if (userRole.equals(RoleCode.ADMIN.getMessage())) {
            // 管理员查询所有普通用户
            List<Long> userIds = permissionService.getAllCommonUser().getData();
            // 根据userIds查询用户信息并分页
            Page<User> page = new Page<>(usersPageDTO.getPage(), usersPageDTO.getPageSize());
            IPage<User> pageResult = usersMapper.selectPage(page, new QueryWrapper<User>().in("user_id", userIds));
            PageResult<UserInfoVO> result = new PageResult<>();
            result.setTotal(pageResult.getSize());
            result.setRecords(pageResult.getRecords().stream().map(user -> {
                UserInfoVO userInfoVO = new UserInfoVO();
                BeanUtils.copyProperties(user, userInfoVO);
                userInfoVO.setRoleCode(RoleCode.USER.getMessage());
                return userInfoVO;
            }).collect(Collectors.toList()));
            // 日志消息
            sendLoggingMessage(userId, request.getRemoteAddr(), UserAction.RESET_PASSWORD.getMessage(), "获取普通用户列表");
            return result;
        }else if (userRole.equals(RoleCode.SUPER_ADMIN.getMessage())) {
            // 超级管理员
            List<UserRoles> rolesList = permissionService.getAllUser().getData();
            HashMap<Long, Integer> hashMap = new HashMap<>();
            for (UserRoles userRoles : rolesList) {
                hashMap.put(userRoles.getUserId(), userRoles.getRoleId());
            }
            // 分页
            Page<User> page = new Page<>(usersPageDTO.getPage(), usersPageDTO.getPageSize());
            List<Long> userIds = rolesList.stream().map(UserRoles::getUserId).collect(Collectors.toList());
            IPage<User> pageResult = usersMapper.selectPage(page, new QueryWrapper<User>().in("user_id", userIds));
            PageResult<UserInfoVO> result = new PageResult<>();
            result.setRecords(pageResult.getRecords().stream().map(user -> {
                UserInfoVO userInfoVO = new UserInfoVO();
                BeanUtils.copyProperties(user, userInfoVO);
                Integer roleId = hashMap.get(user.getUserId());
                if (roleId.equals(RoleCode.USER.getCode())) {
                    userInfoVO.setRoleCode(RoleCode.USER.getMessage());
                }else if (roleId.equals(RoleCode.ADMIN.getCode())) {
                    userInfoVO.setRoleCode(RoleCode.ADMIN.getMessage());
                }else if (roleId.equals(RoleCode.SUPER_ADMIN.getCode())) {
                    userInfoVO.setRoleCode(RoleCode.SUPER_ADMIN.getMessage());
                }
                return userInfoVO;
            }).collect(Collectors.toList()));
            result.setTotal(pageResult.getSize());
            // 日志消息
            sendLoggingMessage(userId, request.getRemoteAddr(), UserAction.RESET_PASSWORD.getMessage(), "获取所有用户列表");
            return result;
        }else if (userRole.equals(RoleCode.USER.getMessage())) {
            // 普通用户 返回自己
            User user = this.query().eq("user_id", userId).one();
            UserInfoVO userInfoVO = new UserInfoVO();
            BeanUtils.copyProperties(user, userInfoVO);
            userInfoVO.setRoleCode(userRole);
            PageResult<UserInfoVO> result = new PageResult<>();
            result.setTotal(1);
            result.setRecords(List.of(userInfoVO));
            sendLoggingMessage(userId, request.getRemoteAddr(), UserAction.RESET_PASSWORD.getMessage(), "查询了自己");
            return result;
        }

        return null;
    }

    /**
     *用户注册
     *分库分表写入用户表 → RPC调用绑定默认角色 → 发送日志消息至MQ
     * @param userRegisterDTO
     * @param request
     * @return
     */
    @Override
    @GlobalTransactional
    public Result<String> register(UserRegisterDTO userRegisterDTO, HttpServletRequest request) {
        // 1.验证填写格式是否错误
        if (!captchaUtil.validate(userRegisterDTO.getCaptchaKey(), userRegisterDTO.getCaptchaCode())) {
            return Result.error(REGISTER_CODE_ERROR);
        }
        if (userRegisterDTO.getEmail().isEmpty()  || userRegisterDTO.getPhone().isEmpty() || userRegisterDTO.getUsername().isEmpty()) {
            return Result.error(REGISTER_INFO_ERROR);
        }
        // 2.验证用户是否存在
        if (this.query().eq("email", userRegisterDTO.getEmail())
                .or()
                .eq("email", userRegisterDTO.getPhone())
                .exists()) {
            return Result.error(REGISTER_USER_EXIST);
        }

        // 3. 用户注册
        // 存入用户表
        User user = new User();
        Long userId = snowflakeIdGenerator.generateId();
        user.setUserId(userId);
        log.info("生成的用户id:{}", userId);
        BeanUtils.copyProperties(userRegisterDTO, user);
        user.setGmtCreate(LocalDateTime.now()); // 创建时间
        this.save(user); // 存入数据库
        // 存入角色表
        permissionService.bindDefaultRole(user.getUserId());

        // 4.封装日志消息
        LoggingMessage loggingMessage = new LoggingMessage();
        loggingMessage.setUserId(user.getUserId());
        loggingMessage.setAction(UserAction.REGISTER.getMessage());
        loggingMessage.setIp(request.getRemoteAddr());
        loggingMessage.setDetail("用户注册成功");
        sendLoggingMessage(loggingMessage);
        System.out.println("日志消息" + loggingMessage.toString());

        return Result.success(REGISTER_SUCCESS);
    }

    /**
     * 发送日志消息
     * @param loggingMessage
     */
    private void sendLoggingMessage(LoggingMessage loggingMessage) {
        rabbitTemplate.convertAndSend(LOGGING_EXCHANGE,LOGGING_ROUTING_KEY, loggingMessage);
    }

    /**
     * 用户登录
     * 用户校验 + 生成Token
     * @param userLoginDTO
     * @return
     */
    @Override
    public Result<UserVO> login(UserLoginDTO userLoginDTO, HttpServletRequest request) {
        // 校验输入
        if (userLoginDTO.getEmail().isEmpty() && userLoginDTO.getPhone().isEmpty()) {
            return Result.error(LOGIN_INFO_ERROR);
        }
        // 1.查询用户是否存在
        User user = new User();
        if (!userLoginDTO.getEmail().isEmpty()) {
            user = this.query().eq("email", userLoginDTO.getEmail()).one();
        }else if (!userLoginDTO.getPhone().isEmpty()){
            user = this.query().eq("phone", userLoginDTO.getPhone()).one();
        }
        log.info("用户: {}", user);
        if (ObjectUtils.isEmpty(user)) {
            // 用户不存在
            return Result.error(LOGIN_USER_NOT_EXIST);
        }
        // 2.校验密码
        if (!userLoginDTO.getPassword().equals(user.getPassword())) {
            return Result.error(LOGIN_PASSWORD_ERROR);
        }

        // 3.封装日志消息
        String detail = JSONObject.toJSONString(user.getUsername());
        sendLoggingMessage(user.getUserId(), request.getRemoteAddr(), UserAction.LOGIN.getMessage(), detail);

        log.info("用户登录: {}", detail);

        // 4.登录成功，生成token存储在redis中
        String token = JwtTokenUtil.generateToken(user.getUserId());
        // 设置过期时间 1个小时
        redisTemplate.expire(USER_TOKEN_PREFIX + token, USER_TOKEN_TTL, TimeUnit.SECONDS);
        redisTemplate.opsForValue().set(USER_TOKEN_PREFIX + token, user.getUserId());
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user, userVO);
        userVO.setToken(token);

        System.err.println(user.getEmail() + "生成的用户token为:" + token);

        // 4.登录成功, 返回给前端
        return Result.success(userVO);
    }



    /**
     * 查询用户信息
     * 根据用户id查询某个用户
     * 如果是超级管理员，则返回所有用户 （管理员和普通用户）
     * 如果是普通用户（只能查看自己的）
     * 如果是管理员，返回普通用户
     * @param userId
     * @return
     */
    @GlobalTransactional(name = "getUserById", rollbackFor = Exception.class)
    @Override
    public Result<UserInfoVO> getUsersById(Long userId, Long currentUserId, HttpServletRequest request) {

        // 1.根据当前用户id查询角色身份
        String roleCode = permissionService.getUserRoleCode(currentUserId).getData();

        System.out.println("当前用户角色：" + roleCode);
        System.out.println("当前用户id:" + currentUserId);
        System.out.println("用户id：" + userId);
        // 2.根据角色身份查询用户信息
        if (roleCode.equals(RoleCode.SUPER_ADMIN.getMessage())) {
            // 超级管理员
            // 1.封装用户信息
            User user = this.query().eq("user_id", userId).one();
            log.info("用户: {}", user);
            if (ObjectUtils.isEmpty(user)) {
                return Result.error(QUERY_USER_NOT_EXIST);
            }
            String queryUserId = permissionService.getUserRoleCode(userId).getData();
            UserInfoVO userInfoVO = new UserInfoVO();
            BeanUtils.copyProperties(user, userInfoVO);
            userInfoVO.setRoleCode(queryUserId);
            // 2.发送日志消息
            QueryLoggingMessage message = new QueryLoggingMessage(currentUserId, userId, LocalDateTime.now());
            String detail = JSONObject.toJSONString(message);
            sendLoggingMessage(userId, request.getRemoteAddr(), UserAction.QUERY.getMessage(), detail);
            log.info("用户查询: {}", detail);

            return Result.success(userInfoVO);

        }else if (roleCode.equals(RoleCode.ADMIN.getMessage())) {
            // 管理员只能查看普通用户
            System.err.println(userId);
            String queryUserId = permissionService.getUserRoleCode(userId).getData();
            System.err.println(queryUserId);

            if (!queryUserId.equals(RoleCode.USER.getMessage())) {
                System.out.println(queryUserId.equals((RoleCode.USER.getMessage())));
                // 没有权限查看
                return Result.error(QUERY_USER_NO_PERMISSION);
            }
            User user = this.query().eq("user_id", userId).one();
            if (user == null || ObjectUtils.isEmpty(user)) {
                return Result.error(QUERY_USER_NOT_EXIST);
            }
            UserInfoVO userInfoVO = new UserInfoVO();
            BeanUtils.copyProperties(user, userInfoVO);
            userInfoVO.setRoleCode(queryUserId);
            // 2.发送日志消息
            QueryLoggingMessage message = new QueryLoggingMessage(currentUserId, userId, LocalDateTime.now());
            String detail = JSONObject.toJSONString(message);
            sendLoggingMessage(currentUserId, request.getRemoteAddr(), UserAction.QUERY.getMessage(), detail);

            return Result.success(userInfoVO);
        }else if (roleCode.equals(RoleCode.USER.getMessage())) {
            // 普通用户只能查看自己
            if (!userId.equals(currentUserId)) {
                // 没有权限查看
                return Result.error(QUERY_USER_NO_PERMISSION);
            }
            User user = this.query().eq("user_id", userId).one();
            UserInfoVO userInfoVO = new UserInfoVO();
            BeanUtils.copyProperties(user, userInfoVO);
            userInfoVO.setRoleCode(RoleCode.USER.getMessage());
            // 发送日志消息
            QueryLoggingMessage message = new QueryLoggingMessage(currentUserId, userId, LocalDateTime.now());
            String detail = JSONObject.toJSONString(message);
            sendLoggingMessage(currentUserId, request.getRemoteAddr(), UserAction.QUERY.getMessage(), detail);

            return Result.success(userInfoVO);
        }
        return Result.error(QUERY_USER_NOT_EXIST);
    }

    /**
     * 发送日志消息
     * @param userId 用户id
     * @param ip ip地址
     * @param action 行为
     * @param detail 详细信息
     */
    private void sendLoggingMessage(Long userId, String ip, String action, String detail) {
        LoggingMessage loggingMessage = new LoggingMessage();
        loggingMessage.setUserId(userId);
        loggingMessage.setAction(action);
        loggingMessage.setIp(ip);
        loggingMessage.setDetail(detail);
        rabbitTemplate.convertAndSend(LOGGING_EXCHANGE,LOGGING_ROUTING_KEY, loggingMessage);
    }

    /**
     * 修改用户信息
     * 根据权限限制：普通用户改自己，管理员改普通用户，超管改所有
     * @param userId
     * @param userUpdateDTO
     * @param request
     * @return
     */
    @Override
    @GlobalTransactional(name = "updateUser", rollbackFor = Exception.class)
    public Result<String> updateUser(Long userId, UserUpdateDTO userUpdateDTO, HttpServletRequest request) {
        Long currentUserId = userUpdateDTO.getCurrentUserId();
        String action = userUpdateDTO.getAction();

        // 1.查询当前用户角色
        String currentRoleCode = permissionService.getUserRoleCode(currentUserId).getData();
        String userRoleCode = permissionService.getUserRoleCode(userId).getData();
        User user = this.query().eq("user_id", userId).one();
        if (ObjectUtils.isEmpty(user)) {
            return Result.error(UPDATE_USER_NOT_EXIST);
        }
        // 日志
        String detail = JSONObject.toJSONString(userUpdateDTO);
        sendLoggingMessage(currentUserId, request.getRemoteAddr(), UserAction.UPDATE.getMessage(), detail);

        // 2. 判断当前用户角色
        if (currentRoleCode.equals(RoleCode.USER.getMessage())) {
            // 普通用户 只能更新自己
            if (!currentUserId.equals(userId)) {
                return Result.error(ILLEGAL_OPERATION);
            }
            updateUser(userUpdateDTO, user);

            return Result.success(UPDATE_USER_SUCCESS);
        }else if (currentRoleCode.equals(RoleCode.ADMIN.getMessage())) {
            // 不能修改超管和管理员
            if (userRoleCode.equals(RoleCode.ADMIN.getMessage()) || userRoleCode.equals(RoleCode.SUPER_ADMIN.getMessage())) {
                return Result.error(ILLEGAL_OPERATION);
            }
            updateUser(userUpdateDTO, user);
//            sendLoggingMessage(currentUserId, request.getRemoteAddr(), UserAction.UPDATE.getMessage(), "用户ID：" + userId);

            return Result.success(UPDATE_USER_SUCCESS);
        }else if (currentRoleCode.equals(RoleCode.SUPER_ADMIN.getMessage())) {
            // 超级管理员
            if (userRoleCode.equals(RoleCode.SUPER_ADMIN.getMessage())) {
                return Result.error(ILLEGAL_OPERATION);
            }
            updateUser(userUpdateDTO, user);
            // 更新权限
            switch (userUpdateDTO.getAction()) {
                case "upgrade":
                    if (userRoleCode.equals(RoleCode.USER.getMessage())) {
                        System.out.println("用户ID：" + userId + "升级为管理员");
                        permissionService.upgradeToAdmin(userId);
//                        String detail = "用户ID：" + userId + "升级为管理员";
//                        sendLoggingMessage(currentUserId, request.getRemoteAddr(), UserAction.UPDATE.getMessage(), detail);
                    }
                    break;
                case "downgrade":
                    if (userRoleCode.equals(RoleCode.ADMIN.getMessage())) {
                        permissionService.downgradeToUser(userId);
//                        String detail = "用户ID：" + userId + "降级为普通用户";
//                        sendLoggingMessage(currentUserId, request.getRemoteAddr(), UserAction.UPDATE.getMessage(), detail);
                    }
                    break;
            }
            return Result.success(UPDATE_USER_SUCCESS);
        }
        return Result.success(UPDATE_USER_SUCCESS);
    }

    /**
     * 更新user对象
     * @param userUpdateDTO
     * @param user
     */
    private void updateUser(UserUpdateDTO userUpdateDTO, User user) {
        if (!userUpdateDTO.getUsername().isEmpty()) {
            user.setUsername(userUpdateDTO.getUsername());
        }
        if (!userUpdateDTO.getEmail().isEmpty()) {
            user.setEmail(userUpdateDTO.getEmail());
        }
        if (!userUpdateDTO.getPhone().isEmpty()) {
            user.setPhone(userUpdateDTO.getPhone());
        }
        this.update().set("username", user.getUsername())
                .set("email", user.getEmail())
                .set("phone", user.getPhone())
                .eq("user_id", user.getUserId())
                .update();
    }

//    /**
//     * 降级为普通用户
//     * @param currentRoleCode
//     * @param currentUserId
//     * @param userId
//     * @param request
//     * @param userRoleCode
//     * @return
//     */
//    private Result<String> downgradeToUser(String currentRoleCode, Long currentUserId, Long userId, HttpServletRequest request, String userRoleCode) {
//        // 如果是普通用户的话，就不能再降级了
//        // 只有超级管理员才能操作管理员
//        if (userRoleCode.equals(RoleCode.USER.getMessage()) || !currentRoleCode.equals(RoleCode.SUPER_ADMIN.getMessage())) {
//            return Result.error(ILLEGAL_OPERATION);
//        }
//        permissionService.downgradeToUser(userId);
//        String detail = String.format("将用户 %s 降级为普通用户", userId);
//        sendLoggingMessage(new LoggingMessage(currentUserId, UserAction.UPDATE.getMessage(), request.getRemoteAddr(), detail));
//        return Result.success(UPDATE_USER_SUCCESS);
//    }
//
//    /**
//     * 升级成管理员
//     * @param currentRoleCode
//     * @param currentUserId
//     * @param userId
//     * @param request
//     * @param userRoleCode
//     * @return
//     */
//    private Result<String> upgradeToAdmin(String currentRoleCode, Long currentUserId, Long userId, HttpServletRequest request, String userRoleCode) {
//        // 当前操作的用户必须是普通用户
//        if (!RoleCode.USER.getCode().equals(currentRoleCode)) {
//            return Result.error(ILLEGAL_OPERATION);
//        }
//        permissionService.upgradeToAdmin(userId);
//        // 发送日志
//        String detail = String.format("将用户 %s 升级为管理员", userId);
//        sendLoggingMessage(currentUserId, request.getRemoteAddr(),UserAction.UPDATE.getMessage(), detail);
//        return Result.success(UPDATE_USER_SUCCESS);
//    }

    /**
     * 重置密码
     * 普通用户重置自己，管理员重置普通用户，超管重置所有人
     * @param passWordResetDTO
     * @param request
     * @return
     */
    @Override
    @GlobalTransactional(name = "resetPassword", rollbackFor = Exception.class)
    public Result<String> resetPassword(PassWordResetDTO passWordResetDTO, HttpServletRequest request) {
        Long currentUserId = passWordResetDTO.getCurrentUserId();
        Long userId = passWordResetDTO.getUserId();
        String currentUserRole = permissionService.getUserRoleCode(currentUserId).getData();
        String userRole = permissionService.getUserRoleCode(userId).getData();
        // 日志
        String detail = JSONObject.toJSONString(passWordResetDTO);
        sendLoggingMessage(userId, request.getRemoteAddr(), UserAction.RESET_PASSWORD.getMessage(), detail);

        if (userRole == null || userRole.isEmpty()) {
            return Result.error(SYSTEM_ERROR);
        }

        if (currentUserRole.equals(RoleCode.USER.getMessage())) {
            // 普通用户
            if (!currentUserId.equals(userId)) {
                return Result.error(ILLEGAL_OPERATION);
            }
            if (!passWordResetDTO.getCurrentUserId().equals(passWordResetDTO.getUserId())) {
                // 非法操作
                return Result.error(ILLEGAL_OPERATION);
            }
            this.update(new UpdateWrapper<User>()
                    .set("password", passWordResetDTO.getPassword())
                    .eq("user_id", userId));

            return Result.success(RESET_PASSWORD_SUCCESS);
        }else if (currentUserRole.equals(RoleCode.ADMIN.getMessage())) {
            // 管理员
            if (!userRole.equals(RoleCode.USER.getMessage())) {
                return Result.error(ILLEGAL_OPERATION);
            }
            this.update(new UpdateWrapper<User>().set("password", passWordResetDTO.getPassword()).eq("user_id", userId));
            return Result.success(RESET_PASSWORD_SUCCESS);
        }else if (currentUserRole.equals(RoleCode.SUPER_ADMIN.getMessage())) {
            if (userRole.equals(RoleCode.SUPER_ADMIN.getMessage())) {
                return Result.error(ILLEGAL_OPERATION);
            }
            this.update(new UpdateWrapper<User>().set("password", passWordResetDTO.getPassword()).eq("user_id", userId));
            return Result.success(RESET_PASSWORD_SUCCESS);
        }
        return Result.success(RESET_PASSWORD_SUCCESS);
    }
}
